import {isEmpty} from '@/utils/CommonUtils';

export default class FormDesignParser {
  formDefinition;
  views;
  parsedViews = [];

  constructor(formDefinition) {
    this.formDefinition = formDefinition;
    this.views = this.formDefinition.views;
  }


  parse() {
    this.resolveDefaultValues();
    this.parseViews();
  }

  parseViews() {
    for (let i = 0; i < this.views.length; i++) {
      this.parseView(this.views[i]);
    }
  }

  parseView(view) {
    let viewDesignDefinition = view.viewDesignDefinition;
    let parseWrapper = this.createParseWrapper(viewDesignDefinition);

    let children = $(parseWrapper).children();
    let result = {
      children: this.parseViewChildren(children)
    };
    view.viewDefinition = JSON.stringify(result);
    this.parsedViews.push(result);
  }

  parseViewChildren(viewChildren) {
    let res = [];
    for (let i = 0; i < viewChildren.length; i++) {
      let child = viewChildren[i];
      if (this.isComponent(child)) {
        res.push(this.parseComponent(child));
      } else if (this.isDavidTable(child)) {
        res.push(this.parseTableComponent(child));
      } else if (this.isSubTable(child)) {
        res.push(this.parseSubTableComponent(child));
      } else {
        //遇到了意外的情况: 这个元素既不是组件, 又不是DavidTable
      }
    }
    return res;
  }

  parseComponent(ele) {
    return {
      type: 'component',
      fieldId: $(ele).attr('id'),
      component: this.getDataComponent(ele),
    };
  }

  parseTableComponent(davidTable) {
    let res = {
      component: 'davidTable',
      type: 'component',
      colWidth: this.parseDavidTableColWidth(davidTable),
      rowHeight: this.parseDavidTableRowHeight(davidTable),
      content: this.parseDavidTableContent(davidTable)
    };
    return res;
  }

  parseDavidTableColWidth(davidTable) {
    let cols = $(davidTable).find('colgroup').find('col');
    let res = [];
    for (let i = 0; i < cols.length; i++) {
      res.push($(cols[i]).width());
    }
    return res;
  }

  parseDavidTableRowHeight(davidTable) {
    let trs = $(davidTable).find('tr');
    let res = [];
    for (let i = 0; i < trs.length; i++) {
      res.push($(trs[i]).height());
    }
    return res;
  }

  parseDavidTableContent(davidTable) {
    let temp = [];
    let trs = $(davidTable).find('tr');
    for (let i = 0; i < trs.length; i++) {
      let tds = $(trs[i]).find('td');
      let trTemp = [];
      for (let j = 0; j < tds.length; j++) {
        let td = tds[j];
        let res = {x: i, y: j};
        res.content = this.parseTdContent(td);
        res.style = this.getTdStyle(td);
        res.colSpan = this.getTdColSpan(td);
        res.rowSpan = this.getTdRowSpan(td);
        trTemp.push(res);
      }
      temp.push(trTemp);
    }
    return temp;
  }

  getTdRowSpan(td) {
    let rowSpan = $(td).attr('rowSpan');
    if (isEmpty(rowSpan)) rowSpan = 1;
    return rowSpan;
  }

  getTdColSpan(td) {
    let colSpan = $(td).attr('colSpan');
    if (isEmpty(colSpan)) colSpan = 1;
    return colSpan;
  }

  getTdStyle(td) {
    let style = $(td).attr('style');
    if (isEmpty(style)) style = '';
    return style;
  }

  parseTdContent(td) {
    let nodes = td.childNodes;
    if (isEmpty(nodes)) return null;
    let res = [];
    for (let i = 0; i < nodes.length; i++) {
      let node = nodes[i];
      if (this.isComponent(node)) {
        res.push(this.parseComponent(node));
      } else {
        res.push({
          type: 'text',
          value: $(node).text()
        });
      }
    }
    return {
      content: res,
      style: this.getTdStyle(td),
      colSpan: this.getTdColSpan(td),
      rowSpan: this.getTdRowSpan(td),
    };
  }

  isComponent(child) {
    let role = this.getDataRole(child);
    let dataComponent = this.getDataComponent(child);
    return role === 'block' && dataComponent !== 'table' && dataComponent !== 'SubTable';
  }

  isDavidTable(ele) {
    let role = this.getDataRole(ele);
    let dataComponent = this.getDataComponent(ele);
    return role === 'block' && dataComponent === 'table' && $(ele).hasClass('david-table');
  }

  getDataRole(ele) {
    return $(ele).attr('data-role');
  }

  getDataComponent(ele) {
    return $(ele).attr('data-component');
  }

  createParseWrapper(content) {
    let res = $(`<div data-role="parse-wrapper"></div>`)[0];
    $(res).html(content);
    return res;
  }

  resolveDefaultValues() {
    if (!this.views) this.views = [];
  }

  isSubTable(ele) {
    let role = this.getDataRole(ele);
    let dataComponent = this.getDataComponent(ele);
    return role === 'block' && $(ele).hasClass('david-table') && dataComponent === 'SubTable';
  }

  parseSubTableComponent(subTable) {
    let {start, end} = this.parseSubTableBodyRowIndex(subTable);
    let length = $(subTable).find('tr').length;

    let subFormId = $(subTable).attr('id');
    let subFormName = this.getSubFormName(subFormId);
    return {
      component: 'SubTable',
      type: 'component',
      subFormId,
      subFormName,
      colWidth: this.parseDavidTableColWidth(subTable),
      rowHeight: this.parseDavidTableRowHeight(subTable),
      header: this.parseSubTableRow(subTable, 0, start),
      body: this.parseSubTableRow(subTable, start, end),
      footer: this.parseSubTableRow(subTable, end, length),
    };
  }

  getSubFormName(subFormId) {
    let subForms = this.formDefinition.subForms;
    if (isEmpty(subForms)) subForms = [];
    let index = subForms.findIndex(s => s.id === subFormId);
    if (index !== -1) {
      return subForms[index].formName;
    }
  }

  parseSubTableRow(davidTable, start, end) {
    let trContent = [];
    let trs = $(davidTable).find('tr');

    for (let i = start; i < end; i++) {
      let tds = $(trs[i]).find('td');
      let tr = [];
      for (let j = 0; j < tds.length; j++) {
        let td = tds[j];
        let content = this.parseTdContent(td);
        tr.push(content);
      }
      trContent.push(tr);
    }
    return trContent;
  }

  parseSubTableBodyRowIndex(davidTable) {
    let trs = $(davidTable).find('tr');
    let start = 10000, end = 0;
    for (let i = 0; i < trs.length; i++) {
      let tr = trs[i];
      if (this.isDetailRole(tr)) {
        start = Math.min(start, i);
        end = Math.max(end, i);
      }
    }
    return {start, end: end + 1};
  }

  isDetailRole(ele) {
    return this.getDataRole(ele) === 'subtable-detail';
  }
};
